package com.smartalarmclock.Model;

import android.annotation.SuppressLint;
import java.sql.Time;
import java.util.Calendar;
import java.util.Date;

public interface ITimeFrame extends IReferencedDataEntity {

	// Methods
	
	/**
	 * @return the start time of the time frame
	 */
	public TimeInWeek GetStartTime();
	
	/**
	 * Sets the start time
	 * @param startTime the start time
	 */
	public void SetStartTime(TimeInWeek startTime);
	
	/**
	 * @return the end time of the time frame
	 */
	public TimeInWeek GetEndTime();
	
	/**
	 * Sets the end time
	 * @param endTime the end time
	 */
	public void SetEndTime(TimeInWeek endTime);
	
	// Inner Members
	
	public enum DayInWeek {
		Sunday (Calendar.SUNDAY),
		Monday (Calendar.MONDAY),
		Tuesday (Calendar.TUESDAY),
		Wednesday (Calendar.WEDNESDAY),
		Thursday (Calendar.THURSDAY),
		Friday (Calendar.FRIDAY),
		Saturday (Calendar.SATURDAY);
		
		private int m_Value;
		private DayInWeek(int value) {
			m_Value = value;
		}
		
		public int GetValue() {
			return m_Value;
		}
		
		public static DayInWeek FromValue(int value) {
			switch (value) {
			case Calendar.SUNDAY:
				return Sunday;
			case Calendar.MONDAY:
				return Monday;
			case Calendar.TUESDAY:
				return Tuesday;
			case Calendar.WEDNESDAY:
				return Wednesday;
			case Calendar.THURSDAY:
				return Thursday;
			case Calendar.FRIDAY:
				return Friday;
			case Calendar.SATURDAY:
				return Saturday;
			}
			
			return null;
		}
	}

	@SuppressLint("DefaultLocale")
	public final class TimeInWeek {
		private static Date s_SundayMorning = new Date(1000 * 60 * 60 * 24 * 3);
		private static long s_SecondInMillisecons = 1000;
		private static long s_MinuteInMilliseconds = s_SecondInMillisecons * 60;
		private static long s_HourInMilliseconds = s_MinuteInMilliseconds * 60;
		private static long s_DayInMilliseconds = s_HourInMilliseconds * 24;
		private static long s_WeekInMilliseconds = s_DayInMilliseconds * 7;
		
		public DayInWeek Day;
		public Time Time;
		
		public TimeInWeek(DayInWeek day, Time time) {
			Day = day;
			Time = time;
		}
		
		public TimeInWeek(DayInWeek day, int hour, int minute, int second) {
			Day = day;
			Time = new Time(s_SundayMorning.getTime() +
				(hour * s_HourInMilliseconds) +
				(minute * s_MinuteInMilliseconds) +
				(second * s_SecondInMillisecons));
		}
		
		/**
		 * Calculates the time in a Date instance without the accurate date.
		 * @param day the day of the week
		 * @param time the time in the day
		 * @param isWraparoud whether we should add a week to the date so the time frame will be a correct range of dates.
		 * @return the matching Date instance
		 */
		public Date CalculateDate(boolean isWraparoud) {
			long calculatedDay = s_SundayMorning.getTime() + ((Day.GetValue() - 1) * s_DayInMilliseconds);
			if (isWraparoud) {
				// Add a week to the date since the time in the week is after Saturday at midnight
				// This is done so the DB query will be easier and faster
				calculatedDay += s_WeekInMilliseconds; 
			}
			
			long calculatedTime = calculatedDay + 
					(Time.getHours() * s_HourInMilliseconds) + 
					(Time.getMinutes() * s_MinuteInMilliseconds) + 
					(Time.getSeconds() * s_SecondInMillisecons);
			
			return new Date(calculatedTime);
		}
		
		/**
		 * @param dateInMilliseconds the date in milliseconds since Jan 1, 1970
		 * @return the day in the week according to the given long timestamp 
		 */
		public static TimeInWeek FromDateInMilliseconds(long dateInMilliseconds) {
			long longDate = dateInMilliseconds - s_SundayMorning.getTime();
			DayInWeek day = DayInWeek.FromValue((int)(longDate / s_DayInMilliseconds) + 1);
			long longTime = longDate % s_DayInMilliseconds;
			return new TimeInWeek(day, new Time(longTime));
		}

		@Override
		public String toString() {
			return String.format("%s %s", Day.toString(), Time.toString());
		}
		
		@Override
		public int hashCode() {
			return toString().hashCode();
		}
	}
}
